<?php
namespace my;

use think\facade\Cache;
use think\Db;
/**
 *  微信信息
 */
class Wx {

    protected $appId;
    protected $appSecret;
    protected $grantType = 'client_credential';

    public function __construct($appId,$appSecret,$grantType = 'client_credential')
    {
        $this->appId        = $appId;
        $this->appSecret    = $appSecret;
        $this->grantType    = $grantType;
    }

    /**
     *  微信公众号授权
     **/
    public function getGzhAuthLogin($code)
    {
        $result    = [
            'status'    =>  false,
            'msg'       =>  '',
            'openid'    =>  '',
            'session_key'=> '',
        ];

        if(!$code)
        {
            return $result;
        }

        $url        = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=$this->appId&secret=$this->appSecret&code=$code&grant_type=$this->grantType";
        $response   = json_decode(request_url($url), true);

        if (!empty($response['errcode'])) {
            $result['msg'] = $response['errmsg'];
            return $result;
        }

        $result['status'] = true;
        $result['openid'] = $response['openid'];
        $result['session_key'] = $response['session_key'];
        return $result;
    }

    /**
     *  微信小程序授权
     **/
    public function getMimiAuthLogin($code)
    {
        $result    = [
            'status'    =>  false,
            'msg'       =>  '',
            'openid'    =>  '',
            'session_key'=> '',
        ];

        if(!$code)
        {
            return $result;
        }

        $url = 'https://api.weixin.qq.com/sns/jscode2session';
        $response = json_decode(request_url($url, [
            'appid'         => $this->appId,
            'secret'        => $this->appSecret,
            'grant_type'    => $this->grantType,
            'js_code'       => $code
        ]), true);

        if (!empty($response['errcode'])) {
            $result['msg'] = $response['errmsg'];
            return $result;
        }

        $result['status'] = true;
        $result['openid'] = $response['openid'];
        $result['session_key'] = $response['session_key'];
        return $result;
    }
    /**
     *  微信公众号 weixin JSSDK 信息
     **/
    public function getLocationInfo($url)
    {
        $jsapi_ticket = $this->getJsApiTicket();

        // 注意 URL 一定要动态获取，不能 hardcode.
//        $protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off' || $_SERVER['SERVER_PORT'] == 443) ? "https://" : "http://";
//        $url = "$protocol$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
//        $url = getUrl().'/h5/';
        $url = urldecode($url);
        $timestamp = time();
        $nonceStr = $this->createNonceStr();

        // 这里参数的顺序要按照 key 值 ASCII 码升序排序
        $string = "jsapi_ticket=$jsapi_ticket&noncestr=$nonceStr&timestamp=$timestamp&url=$url";

        $sign = sha1($string);
        $param = [
            'appId'=>$this->appId,
            'timestamp'=>"$timestamp",
            "url"       => $url,
            'nonceStr'=>$nonceStr,
            'signature'=>$sign,
        ];
        return $param;
    }


    private function createNonceStr($length = 16) {
        $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        $str = "";
        for ($i = 0; $i < $length; $i++) {
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }


    /**
     *  获取 wx getJsApiTicket
     **/
    public function getJsApiTicket()
    {
        $accessToken = $this->getWxAccessToken();
        if(!$accessToken) return false;

        $wxToken = Db::name('qt_wx_token')->where('appid',$this->appId)->find();
        if($wxToken['ticket_time'] < time())
        {
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=".$accessToken."&type=jsapi";
            $response = request_url($url);
            $response = json_decode($response,true);
            if(isset($response['errcode']) && $response['errcode'] != 0)
            {
                return false;
            }
            $jsapi_ticket = $response['ticket'];

            $update['jsapi_ticket'] = $jsapi_ticket;
            $update['ticket_time']  = time() + 7100;
            Db::name('qt_wx_token')->where('appid',$this->appId)->update($update);
        }else{
            $jsapi_ticket = $wxToken['jsapi_ticket'];
        }

        return $jsapi_ticket;
    }

    /**
     *  获取 wx accessToken
     **/
    public function getWxAccessToken()
    {

        $wxToken = Db::name('qt_wx_token')->where('appid',$this->appId)->find();
        if($wxToken['token_time'] < time()||empty($wxToken))
        {
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=$this->grantType&appid=$this->appId&secret=$this->appSecret";
            $response = request_url($url);
            $response = json_decode($response,true);
            // p($response);
            if(isset($response['errcode']) && $response['errcode'] != 0)
            {
                return false;
            }
            $accessToken = $response['access_token'];

            $update['access_token'] = $accessToken;
            $update['token_time']   = time() + 7100;
            Db::name('qt_wx_token')->where('appid',$this->appId)->update($update);
        }else{
            $accessToken = $wxToken['access_token'];
        }

        return $accessToken;
    }


    /**
     * 检验数据的真实性，并且获取解密后的明文.
     * @param $encryptedData string 加密的用户数据
     * @param $iv string 与用户数据一同返回的初始向量
     * @param $data string 解密后的原文
     *
     * @return int 成功0，失败返回对应的错误码
     */
    function decryptData( $encryptedData, $iv, $sessionKey)
    {
        if (strlen($sessionKey) != 24) {
            return false;
        }
        $aesKey=base64_decode($sessionKey);


        if (strlen($iv) != 24) {
            return false;
        }
        $aesIV=base64_decode($iv);

        $aesCipher=base64_decode($encryptedData);

        $result=openssl_decrypt( $aesCipher, "AES-128-CBC", $aesKey, 1, $aesIV);
        $dataObj = json_decode($result,true);
        if(!$dataObj)
        {
            return false;
        }
        return $dataObj;
    }

}

?>